home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / FS.PY < prev    next >
Encoding:
Python Source  |  1999-07-14  |  12.3 KB  |  418 lines

  1. ##############################################################################
  2. # Zope Public License (ZPL) Version 1.0
  3. # -------------------------------------
  4. # Copyright (c) Digital Creations.  All rights reserved.
  5. # This license has been certified as Open Source(tm).
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are
  8. # met:
  9. # 1. Redistributions in source code must retain the above copyright
  10. #    notice, this list of conditions, and the following disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above copyright
  12. #    notice, this list of conditions, and the following disclaimer in
  13. #    the documentation and/or other materials provided with the
  14. #    distribution.
  15. # 3. Digital Creations requests that attribution be given to Zope
  16. #    in any manner possible. Zope includes a "Powered by Zope"
  17. #    button that is installed by default. While it is not a license
  18. #    violation to remove this button, it is requested that the
  19. #    attribution remain. A significant investment has been put
  20. #    into Zope, and this effort will continue if the Zope community
  21. #    continues to grow. This is one way to assure that growth.
  22. # 4. All advertising materials and documentation mentioning
  23. #    features derived from or use of this software must display
  24. #    the following acknowledgement:
  25. #      "This product includes software developed by Digital Creations
  26. #      for use in the Z Object Publishing Environment
  27. #      (http://www.zope.org/)."
  28. #    In the event that the product being advertised includes an
  29. #    intact Zope distribution (with copyright and license included)
  30. #    then this clause is waived.
  31. # 5. Names associated with Zope or Digital Creations must not be used to
  32. #    endorse or promote products derived from this software without
  33. #    prior written permission from Digital Creations.
  34. # 6. Modified redistributions of any form whatsoever must retain
  35. #    the following acknowledgment:
  36. #      "This product includes software developed by Digital Creations
  37. #      for use in the Z Object Publishing Environment
  38. #      (http://www.zope.org/)."
  39. #    Intact (re-)distributions of any official Zope release do not
  40. #    require an external acknowledgement.
  41. # 7. Modifications are encouraged but must be packaged separately as
  42. #    patches to official Zope releases.  Distributions that do not
  43. #    clearly separate the patches from the original work must be clearly
  44. #    labeled as unofficial distributions.  Modifications which do not
  45. #    carry the name Zope may be packaged in any form, as long as they
  46. #    conform to all of the clauses above.
  47. # Disclaimer
  48. #   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
  49. #   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  50. #   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  51. #   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
  52. #   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  53. #   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  54. #   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  55. #   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  56. #   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  57. #   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  58. #   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  59. #   SUCH DAMAGE.
  60. # This software consists of contributions made by Digital Creations and
  61. # many individuals on behalf of Digital Creations.  Specific
  62. # attributions are listed in the accompanying credits file.
  63. ##############################################################################
  64.  
  65. import struct, tempfile, string, time, pickle, os, sys
  66. from struct import pack, unpack
  67. from cStringIO import StringIO
  68.  
  69. class FS:
  70.     """FileStorage 'report' writer for converting BoboPOS to FileStorage
  71.     """
  72.  
  73.  
  74.     def __init__(self, fname, file):
  75.         file.seek(0,2)
  76.         self._input_size=file.tell()
  77.         file.seek(0)
  78.         self.__name__=fname
  79.         self._file=open(fname,'w+b')
  80.         self._file.write('FS21')
  81.  
  82.         self._index={}
  83.         self._indexpos=self._index.get
  84.         self._tindex=[]
  85.         self._tappend=self._tindex.append
  86.         self._tfile=tempfile.TemporaryFile()
  87.         self._pos=4
  88.         self._progress=None
  89.         
  90.  
  91.     def rpt(self, pos, oid, start, tname, user, t, p, first, newtrans):
  92.         if pos is None:
  93.             self.tpc_finish()
  94.             sys.stderr.write(' %% 100     \n')
  95.             return
  96.         else:
  97.             progress=' %% %.1f \r' % (pos*100.0/self._input_size)
  98.             if progress != self._progress:
  99.                 sys.stderr.write(progress)
  100.                 self._progress=progress
  101.  
  102.         if newtrans:
  103.             try: string.atof(tname)
  104.             except:
  105.                 # Ugh, we have a weird tname.  We'll just ignore the transaction
  106.                 # boundary and merge transactions
  107.                 if first:
  108.                     # But we can't ignore the first one, so we'll hack in a
  109.                     # bogus start date
  110.                     self.tpc_begin('100', user, t)
  111.             else:
  112.                 if not first: self.tpc_finish()
  113.                 self.tpc_begin(tname, user, t)
  114.         self.store(oid, p)
  115.  
  116.     def store(self, oid, data):
  117.         old=self._indexpos(oid, 0)
  118.         pnv=None
  119.  
  120.         tfile=self._tfile
  121.         write=tfile.write
  122.         pos=self._pos
  123.         here=tfile.tell()+pos+self._thl
  124.         self._tappend(oid, here)
  125.         serial=self._serial
  126.         data=fixpickle(data, oid)
  127.         write(pack(">8s8s8s8sH8s",
  128.                    p64(oid+1),serial,p64(old),p64(pos),
  129.                    0,p64(len(data))
  130.                    )
  131.               )
  132.  
  133.         write(data)
  134.  
  135.     def tpc_begin(self, tname, user, desc):
  136.         del self._tindex[:]   # Just to be sure!
  137.         self._tfile.seek(0)
  138.  
  139.         t=string.atof(tname)
  140.         y,m,d,h,mi=time.gmtime(t)[:5]
  141.         s=t%60
  142.         self._serial=struct.pack(
  143.             ">II",
  144.             (((((y-1900)*12)+m-1)*31+d-1)*24+h)*60+mi,
  145.             long(s * (1L << 32) / 60)
  146.             )
  147.  
  148.         # Ugh, we have to record the transaction header length
  149.         # so that we can get version pointers right.
  150.         self._thl=23+len(user)+len(desc)
  151.  
  152.         # And we have to save the data used to compute the
  153.         # header length. It's unlikely that this stuff would
  154.         # change, but if it did, it would be a disaster.
  155.         self._ud=user, desc
  156.  
  157.     def tpc_finish(self):
  158.         file=self._file
  159.         write=file.write
  160.         tfile=self._tfile
  161.         dlen=tfile.tell()
  162.         tfile.seek(0)
  163.         id=self._serial
  164.         user, desc = self._ud
  165.         self._ud=None
  166.                         
  167.         tlen=self._thl
  168.         pos=self._pos
  169.         tl=tlen+dlen
  170.         stl=p64(tl)
  171.         write(pack(
  172.             ">8s" "8s" "c"  "H"        "H"        "H"
  173.             ,id, stl, ' ', len(user), len(desc), 0,
  174.             ))
  175.         if user: write(user)
  176.         if desc: write(desc)
  177.             
  178.         cp(tfile, file, dlen)
  179.                 
  180.         write(stl)
  181.         self._pos=pos+tl+8
  182.  
  183.         tindex=self._tindex
  184.         index=self._index
  185.         for oid, pos in tindex: index[oid]=pos
  186.         del tindex[:]
  187.  
  188.  
  189. class ZEXP:
  190.     """Zope Export format 'report' writer
  191.     """
  192.     def __init__(self, fname, file):
  193.         file.seek(0,2)
  194.         self._input_size=file.tell()
  195.         file.seek(0)
  196.         self.__name__=fname
  197.         self._file=open(fname,'w+b')
  198.         self._file.write('ZEXP')
  199.  
  200.         self._pos=4
  201.         self._progress=None
  202.         
  203.  
  204.     def rpt(self, pos, oid, start, tname, user, t, p, first, newtrans):
  205.         write=self._file.write
  206.         if pos is None:
  207.             write('\377'*16) # end marker
  208.             sys.stderr.write(' %% 100     \n')
  209.             return
  210.         else:
  211.             progress=' %% %.1f \r' % (pos*100.0/self._input_size)
  212.             if progress != self._progress:
  213.                 sys.stderr.write(progress)
  214.                 self._progress=progress
  215.  
  216.         data=fixpickle(p, oid)
  217.         l=len(data)
  218.         write(p64(oid+1)+p64(l))
  219.         write(data)
  220.         self._pos=self._pos+l+16
  221.  
  222.  
  223. t32 = 1L << 32
  224.  
  225. def p64(v, pack=struct.pack):
  226.     if v < t32: h=0
  227.     else:
  228.         h=v/t32
  229.         v=v%t32
  230.     return pack(">II", h, v)
  231.  
  232. def cp(f1, f2, l):
  233.     read=f1.read
  234.     write=f2.write
  235.     n=8192
  236.     
  237.     while l > 0:
  238.         if n > l: n=l
  239.         d=read(n)
  240.         write(d)
  241.         l = l - len(d)
  242.  
  243.     
  244. class Ghost: pass
  245.  
  246. class Global:
  247.     __safe_for_unpickling__=1
  248.     
  249.     def __init__(self, m, n):
  250.         self._module, self._name = m, n
  251.  
  252.     def __call__(self, *args):
  253.         return Inst(self, args)
  254.  
  255.     def __basicnew__(self):
  256.         return Inst(self, None)
  257.  
  258. def _global(m, n):
  259.     if m[:8]=='BoboPOS.':
  260.         if m=='BoboPOS.PickleDictionary' and n=='Root':
  261.             m='ZODB.conversionhack'
  262.             n='hack'
  263.         elif m=='BoboPOS.PersistentMapping': m='Persistence'
  264.         elif m=='BoboPOS.cPickleJar' and n=='ec':
  265.             m=n='ExtensionClass'
  266.         else:
  267.             raise 'Unexpected BoboPOS class', (m, n)
  268.     elif m=='PersistentMapping': m='Persistence'
  269.  
  270.     return Global(m,n)
  271.     
  272.  
  273. class Inst:
  274.  
  275.     _state=None
  276.     
  277.     def __init__(self, c, args):
  278.         self._cls=c
  279.         self._args=args
  280.  
  281.     def __setstate__(self, state): self._state=state
  282.  
  283.  
  284. from pickle import INST, GLOBAL, MARK, BUILD, OBJ, REDUCE
  285.  
  286. InstanceType=type(Ghost())
  287.  
  288. class Unpickler(pickle.Unpickler):
  289.  
  290.     dispatch={}
  291.     dispatch.update(pickle.Unpickler.dispatch)
  292.  
  293.     def load_inst(self):
  294.         k = self.marker()
  295.         args = tuple(self.stack[k+1:])
  296.         del self.stack[k:]
  297.         module = self.readline()[:-1]
  298.         name = self.readline()[:-1]
  299.         klass = _global(module, name)
  300.         value=Inst(klass, args)
  301.         self.append(value)
  302.             
  303.     dispatch[INST] = load_inst
  304.  
  305.     def load_global(self):
  306.         module = self.readline()[:-1]
  307.         name = self.readline()[:-1]
  308.         klass = _global(module, name)
  309.         self.append(klass)
  310.     dispatch[GLOBAL] = load_global
  311.  
  312.     def persistent_load(self, oid,
  313.                         TupleType=type(()), Ghost=Ghost, p64=p64):
  314.         "Remap object ids from ZODB 2 stype to ZODB 3 style"
  315.  
  316.         if type(oid) is TupleType:
  317.             oid, klass = oid
  318.             oid = p64(oid+1), klass
  319.         else:
  320.             oid = p64(oid+1)
  321.             
  322.         Ghost=Ghost()
  323.         Ghost.oid=oid
  324.         return Ghost
  325.  
  326.  
  327. class Pickler(pickle.Pickler):
  328.  
  329.     dispatch={}
  330.     dispatch.update(pickle.Pickler.dispatch)
  331.  
  332.     def persistent_id(self, object, Ghost=Ghost):
  333.         if hasattr(object, '__class__') and object.__class__ is Ghost:
  334.             return object.oid
  335.  
  336.     def save_inst(self, object):
  337.         d = id(object)
  338.         cls = object.__class__
  339.  
  340.         memo  = self.memo
  341.         write = self.write
  342.         save  = self.save
  343.  
  344.         if cls is Global:
  345.             memo_len = len(memo)
  346.             write(GLOBAL + object._module + '\n' + object._name + '\n' +
  347.                   self.put(memo_len))
  348.             memo[d] = (memo_len, object)
  349.             return
  350.  
  351.         self.save_inst(object._cls)
  352.         save(object._args)
  353.  
  354.         memo_len = len(memo)
  355.         write(REDUCE + self.put(memo_len))
  356.  
  357.         memo[d] = (memo_len, object)
  358.  
  359.         stuff=object._state
  360.         save(stuff)
  361.         write(BUILD)
  362.  
  363.     dispatch[InstanceType] = save_inst
  364.  
  365.     def save_global(self, object, name = None):
  366.         write = self.write
  367.         memo = self.memo
  368.  
  369.         if (name is None):
  370.             name = object._name
  371.  
  372.         module=object._module
  373.  
  374.         memo_len = len(memo)
  375.         write(GLOBAL + module + '\n' + name + '\n' +
  376.             self.put(memo_len))
  377.         memo[id(object)] = (memo_len, object)
  378.  
  379.     dispatch[type(Ghost)] = save_global
  380.     
  381.     
  382. def fixpickle(p, oid):
  383.     
  384.     pfile=StringIO(p)
  385.     unpickler=Unpickler(pfile)
  386.  
  387.     newp=StringIO()
  388.     pickler=Pickler(newp,1)
  389.  
  390.     pickler.dump(unpickler.load())
  391.     state=unpickler.load()
  392.     if oid==-1: state={'_container': state}
  393.     pickler.dump(state)
  394.     p=newp.getvalue()
  395.  
  396.     return p
  397.